class: title-slide, right, top background-image: url(data:image/png;base64,#img/hex_ggplot2.png), url(img/axsome_logo.png) background-position: 93% 63%, 50% 50% background-size: 10%, 40%
.right-column[ # Module 3: Data Visualization ### A First Foray Into ggplot2 **Graham Eglit**<br> Axsome Therapeutics<br> Fall 2024 ] --- class: inverse, center, middle # Graphics Have Grammars? ---- <svg viewBox="0 0 581 512" style="position:relative;display:inline-block;top:.1em;fill:white;height:3em;" xmlns="http://www.w3.org/2000/svg"> <path d="M581 226.6C581 119.1 450.9 32 290.5 32S0 119.1 0 226.6C0 322.4 103.3 402 239.4 418.1V480h99.1v-61.5c24.3-2.7 47.6-7.4 69.4-13.9L448 480h112l-67.4-113.7c54.5-35.4 88.4-84.9 88.4-139.7zm-466.8 14.5c0-73.5 98.9-133 220.8-133s211.9 40.7 211.9 133c0 50.1-26.5 85-70.3 106.4-2.4-1.6-4.7-2.9-6.4-3.7-10.2-5.2-27.8-10.5-27.8-10.5s86.6-6.4 86.6-92.7-90.6-87.9-90.6-87.9h-199V361c-74.1-21.5-125.2-67.1-125.2-119.9zm225.1 38.3v-55.6c57.8 0 87.8-6.8 87.8 27.3 0 36.5-38.2 28.3-87.8 28.3zm-.9 72.5H365c10.8 0 18.9 11.7 24 19.2-16.1 1.9-33 2.8-50.6 2.9v-22.1z"></path></svg> --- .center[ # Grammar of Graphics ] .pull-left[ - Proposed by Leland Wilkinson in 2005 - Attempt to describe the essential features that underlie all statistical graphics 1. Graph is a mapping of data to aesthetic attributes (color, shape, size) of geometric objects (lines, bars, points) 1. Graph may contain statistical transformations of the data 1. Graph is drawn on a specific coordinate system 1. Facetting can be used to create small mulitiples of graphs ] .pull-right[ .center[<img src = "data:image/png;base64,#img/mod3/grammar.jpg" height = "20%" width = "50%" />] ] --- .center[ # Fundamental Components of a Graph ] .pull-left[ 1. **Data** to visualize and **aesthetic mappings** of how aesthetics are applied to data 1. **Layers** of geometric elements and statistical transformations - **geoms** are what you see on the plot (e.g., lines, points, etc.) - **stats** summarize data (e.g., group mean) 1. **Scales** map values in data space to values in an aesthetic space 1. **Coord**inates describe how data coordinates are mapped to the plane of the graphic 1. **Facet**ing describes how to break up data into subsets (e.g., small multiples) 1. **Theme** controls finer points of display (e.g., font size, background color, etc.) ] .pull-right[ <br> .center[<img src = "data:image/png;base64,#img/mod3/gglayers.png" />] ] --- class: inverse, center, middle # Let's Get Plotting! ---- <svg viewBox="0 0 512 512" style="position:relative;display:inline-block;top:.1em;fill:white;height:3em;" xmlns="http://www.w3.org/2000/svg"> <path d="M496 384H64V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM464 96H345.94c-21.38 0-32.09 25.85-16.97 40.97l32.4 32.4L288 242.75l-73.37-73.37c-12.5-12.5-32.76-12.5-45.25 0l-68.69 68.69c-6.25 6.25-6.25 16.38 0 22.63l22.62 22.62c6.25 6.25 16.38 6.25 22.63 0L192 237.25l73.37 73.37c12.5 12.5 32.76 12.5 45.25 0l96-96 32.4 32.4c15.12 15.12 40.97 4.41 40.97-16.97V112c.01-8.84-7.15-16-15.99-16z"></path></svg> --- .center[ # First, The Dataset ]
--- .center[ # Create your first ggplot! ] .pull-left[ - Use `ggplot()` to initialize the plot - Creates a coordinate system to add layers to - Supply data to the plot using the `data` argument - Add layers of geoms to the plot - Geoms require aesthetic mappings - Use `mapping` argument and `aes` function to specify ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) ``` ] .pull-right[ <!-- --> ] --- .center[ # Additional Aesthetic Specifications ] - We can supply additional aesthetic specifications in the `aes()` function (e.g., color, size, shape, alpha, fill) and map these to variables in your data set -- .panelset[ .panel[.panel-name[Color] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, color = class)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Size] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, size = class)) ``` ``` ## Warning: Using size for a discrete variable is not advised. ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Alpha] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, alpha = class)) ``` ``` ## Warning: Using alpha for a discrete variable is not advised. ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Shape] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, shape = class)) ``` ``` ## Warning: The shape palette can deal with a maximum of 6 discrete values because ## more than 6 becomes difficult to discriminate; you have 7. Consider ## specifying shapes manually if you must have them. ``` ``` ## Warning: Removed 62 rows containing missing values (`geom_point()`). ``` ] .pull-right[ <!-- --> ] ]<!----> ]<!--end panelset--> --- .center[ # Additional Aesthetic Specifications ] - We can supply additional aesthetic specifications in the `aes()` function (e.g., color, size, shape, alpha, fill) and map these to variables in your data set .panelset[ .panel[.panel-name[Color] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, color = class)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Size] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, size = class)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Alpha] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, alpha = class)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Shape] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, shape = class)) ``` ] .pull-right[ <!-- --> ] ]<!----> ]<!--end panelset--> --- .center[ # Location, Location, Location! ] - You can also set aesthetic properties of a geom manually - But pay attention to the location of the specification! .panelset[ .panel[.panel-name[Correct Manual Color] .center[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy), color = "blue") ``` <!-- --> ] ]<!----> .panel[.panel-name[Incorrect Manual Color] .center[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, color = "blue")) ``` <!-- --> ] ]<!----> ]<!--end panelset--> --- .center[ # Now You Try! ] - Map a continuous variable to `color`, `size`, `shape`, and `alpha`. How do these aesthetics behave differently for categorical versus continuous variables?
03
:
00
--- .center[ # Let's See! ] .panelset[ .panel[.panel-name[Color] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, color = cty)) ``` ] .pull-right[ <!-- --> ] ] <!----> .panel[.panel-name[Size] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, size = cty)) ``` ] .pull-right[ <!-- --> ] ] <!----> .panel[.panel-name[Shape] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, shape = cty)) ``` ``` ## Error in `geom_point()`: ## ! Problem while computing aesthetics. ## ℹ Error occurred in the 1st layer. ## Caused by error in `scale_f()`: ## ! A continuous variable cannot be mapped to the shape aesthetic ## ℹ choose a different aesthetic or use `scale_shape_binned()` ``` ] ] <!----> .panel[.panel-name[Alpha] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, alpha = cty)) ``` ] .pull-right[ <!-- --> ] ] <!----> ] <!--end of panelset--> --- .center[ # Facet-nating ] - Facets create small multiples of plots for each level of a categorical variables using `facet_wrap()` and `facet_grid()` .panelset[ .panel[.panel-name[Facet Wrap] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + facet_wrap(~ class, nrow = 2) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Facet Grid] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + facet_grid(drv ~ cyl) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Horizontal Facet] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + facet_grid(. ~ cyl) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Vertical Facet] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + facet_grid(cyl ~ .) ``` ] .pull-right[ <!-- --> ] ]<!----> ]<!--end panelset--> --- .center[ # Geometric Objects ] - There are many different `geoms` - The type of `geom` often defines the type of graph (e.g., line, bar, boxplot, etc.) - Different geoms may have different arguments (e.g., `method` for `geom_smooth`) .panelset[ .panel[.panel-name[Scatter] .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Smooth, "loess"] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy), method = "loess") ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Smooth, "lm"] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy), method = "lm") ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Smooth, "gam"] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy), method = "gam") ``` ] .pull-right[ <!-- --> ] ]<!----> ]<!--end panel set--> --- .center[ # Getting More from Your Plots ] - We can use additional specifications to: - Look at different smooth lines as a function of a third variable - Overlay raw points on our plot -- .panelset[ .panel[.panel-name[Linetype] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, linetype = drv)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Color] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Overlay Points] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy)) + geom_point(mapping = aes(x = displ, y = hwy)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Overlay Points and Color!] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv)) + geom_point(mapping = aes(x = displ, y = hwy, color = drv)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Fill] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv, fill = drv)) + geom_point(mapping = aes(x = displ, y = hwy, color = drv)) ``` ] .pull-right[ <!-- --> ] ]<!----> ]<!--end panel set--> --- .center[ # Location, Location, Location - Part 2! ] - These two specifications produce the same plot - Aesthetic mappings in a `ggplot()` function are passed on to all subsequent geoms .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv, fill = drv)) + geom_point(mapping = aes(x = displ, y = hwy, color = drv)) ``` <!-- --> ] .pull-right[ ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv, fill = drv)) + geom_smooth() + geom_point() ``` <!-- --> ] --- .center[ # Let's Make a Mistake ] - What do you think will happen if I run the following code? ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy), color = drv) ``` -- ``` ## Error in list2(na.rm = na.rm, orientation = orientation, se = se, ...): object 'drv' not found ``` --- .center[ # Let's Work with a New Dataset! ] <table> <caption>diamonds dataset</caption> <thead> <tr> <th style="text-align:right;"> carat </th> <th style="text-align:left;"> cut </th> <th style="text-align:left;"> color </th> <th style="text-align:left;"> clarity </th> <th style="text-align:right;"> depth </th> <th style="text-align:right;"> table </th> <th style="text-align:right;"> price </th> <th style="text-align:right;"> x </th> <th style="text-align:right;"> y </th> <th style="text-align:right;"> z </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 0.23 </td> <td style="text-align:left;"> Ideal </td> <td style="text-align:left;"> E </td> <td style="text-align:left;"> SI2 </td> <td style="text-align:right;"> 61.5 </td> <td style="text-align:right;"> 55 </td> <td style="text-align:right;"> 326 </td> <td style="text-align:right;"> 3.95 </td> <td style="text-align:right;"> 3.98 </td> <td style="text-align:right;"> 2.43 </td> </tr> <tr> <td style="text-align:right;"> 0.21 </td> <td style="text-align:left;"> Premium </td> <td style="text-align:left;"> E </td> <td style="text-align:left;"> SI1 </td> <td style="text-align:right;"> 59.8 </td> <td style="text-align:right;"> 61 </td> <td style="text-align:right;"> 326 </td> <td style="text-align:right;"> 3.89 </td> <td style="text-align:right;"> 3.84 </td> <td style="text-align:right;"> 2.31 </td> </tr> <tr> <td style="text-align:right;"> 0.23 </td> <td style="text-align:left;"> Good </td> <td style="text-align:left;"> E </td> <td style="text-align:left;"> VS1 </td> <td style="text-align:right;"> 56.9 </td> <td style="text-align:right;"> 65 </td> <td style="text-align:right;"> 327 </td> <td style="text-align:right;"> 4.05 </td> <td style="text-align:right;"> 4.07 </td> <td style="text-align:right;"> 2.31 </td> </tr> <tr> <td style="text-align:right;"> 0.29 </td> <td style="text-align:left;"> Premium </td> <td style="text-align:left;"> I </td> <td style="text-align:left;"> VS2 </td> <td style="text-align:right;"> 62.4 </td> <td style="text-align:right;"> 58 </td> <td style="text-align:right;"> 334 </td> <td style="text-align:right;"> 4.20 </td> <td style="text-align:right;"> 4.23 </td> <td style="text-align:right;"> 2.63 </td> </tr> <tr> <td style="text-align:right;"> 0.31 </td> <td style="text-align:left;"> Good </td> <td style="text-align:left;"> J </td> <td style="text-align:left;"> SI2 </td> <td style="text-align:right;"> 63.3 </td> <td style="text-align:right;"> 58 </td> <td style="text-align:right;"> 335 </td> <td style="text-align:right;"> 4.34 </td> <td style="text-align:right;"> 4.35 </td> <td style="text-align:right;"> 2.75 </td> </tr> <tr> <td style="text-align:right;"> 0.24 </td> <td style="text-align:left;"> Very Good </td> <td style="text-align:left;"> J </td> <td style="text-align:left;"> VVS2 </td> <td style="text-align:right;"> 62.8 </td> <td style="text-align:right;"> 57 </td> <td style="text-align:right;"> 336 </td> <td style="text-align:right;"> 3.94 </td> <td style="text-align:right;"> 3.96 </td> <td style="text-align:right;"> 2.48 </td> </tr> </tbody> </table> --- .center[ # Statistical Transformations ] .pull-left[ - Statistical transformations are any instance in which new values are calculated in the process of creating a plot - Not present in scatter plots - But we did see them in our smooth line plots ] .pull-right[ <!-- --> ] --- .center[ # Bar Charts ] - Bar charts are a prototypical example of a statistical transformation - Note that bar charts present the frequency count of a variable - But frequency count was not a variable in our original dataset! .panelset[ .panel[.panel-name[Bar Chart Plot] .pull-left[ ```r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Bar Chart Transformation] .center[<img src = "data:image/png;base64,#img/mod3/transform.png" height = "5%" width = "60%" /> <br> .caption[Figure from [R for Data Science](https://r4ds.had.co.nz/data-visualisation.html)] ] ]<!----> .panel[.panel-name[Default Transformation] .center[<img src = "data:image/png;base64,#img/mod3/bar_help.png" width = "40%" />] ]<!----> .panel[.panel-name[stat_count] .pull-left[ ```r ggplot(data = diamonds) + stat_count(mapping = aes(x = cut)) ``` ] .pull-right[ <!-- --> ] ]<!----> ]<!--end panel set--> --- .center[ # Changing the Default Transformation ] - use the `stat` argument to change the default transformatoin .pull-left[ ```r dat <- data.frame(group = c("group_a", "group_b", "group_c"), group_mean = c(32, 25, 44)) dat ``` ``` ## group group_mean ## 1 group_a 32 ## 2 group_b 25 ## 3 group_c 44 ``` ] .pull-right[ ```r ggplot(dat) + geom_bar(mapping = aes(x = group, y = group_mean), stat = "identity") ``` <!-- --> ] --- .center[ # Statistical Transformation Summary ] - Each `geom` has a default statistical transformation <br> <br> - Each `stat` in turn has a default geometric object <br> <br> - `stat_` can often be used interchangeably with `geom_` <br> <br> - We often needn't worry about the statistical transformation when using a `geom` because of these defaults <br> <br> - However, we can change the default transformation if necessary --- .center[ # Let's Try Adding Some Color! ] - What will happen if I map `cut` to color for a bar plot? What will happen if I map `cut` to fill? -- .panelset[ .panel[.panel-name[Color Mapping] .pull-left[ ```r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, color = cut)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Fill Mapping] .pull-left[ ```r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = cut)) ``` ] .pull-right[ <!-- --> ] ]<!----> ]<!--end panel set--> --- .center[ # Position Adjustment ] .panelset[ .panel[.panel-name[Default Stack] .left-column[ - Bars are stacked by default - Each colored rectangle is a combination of cut and clarity ] .right-column[ ```r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = clarity)) ``` <!-- --> ] ]<!----> .panel[.panel-name[Fill] .left-column[ - To change positioning, use the `position` argument - "fill" will retain stacking, but stacked bars will be the same height - good for comparing proportions ] .right-column[ ```r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = clarity), position = "fill") ``` <!-- --> ] ]<!----> .panel[.panel-name[Dodge] .left-column[ - To position side-by-side, use `position = "dodge"` ] .right-column[ ```r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = clarity), position = "dodge") ``` <!-- --> ] ]<!----> ]<!--end panel set--> --- .center[ # Scatterplot Position Adjustment ] - Some of the data points overlaped with one another - Use `position = "jitter"` to slightly perturb the position of points .pull-left[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) ``` <!-- --> ] .pull-right[ ```r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy), position = "jitter") ``` <!-- --> ] --- .center[ # Coordinate Systems ] - The Cartesian coordinate system is the default for ggplot and is the one we'll mostly use - Flipping x and y coordinates is often useful - There are others that are important, especially for spatial data, but we won't cover them .panelset[ .panel[.panel-name[Original] .pull-left[ ```r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = cut)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[`coord_flip`] .pull-left[ ```r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = cut)) + coord_flip() ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[Specify in `aes`] .pull-left[ ```r ggplot(data = diamonds) + geom_bar(mapping = aes(y = cut, fill = cut)) ``` ] .pull-right[ <!-- --> ] ]<!----> ]<!--end panel set--> --- .center[ # Themes! ] - Themes control the finer points of display, like font type, font size, thickness of axes, tick marks, etc. - You can create your own theme or use pre-created themes in `ggplot2` or extension packages (like ggthemes) - Below are some examples of alternative `ggplot2` themes .panelset[ .panel[.panel-name[Default] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv, fill = drv)) + geom_point(mapping = aes(x = displ, y = hwy, color = drv)) ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[`theme_minimal`] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv, fill = drv)) + geom_point(mapping = aes(x = displ, y = hwy, color = drv)) + theme_minimal() ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[`theme_dark`] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv, fill = drv)) + geom_point(mapping = aes(x = displ, y = hwy, color = drv)) + theme_dark() ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[`theme_light`] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv, fill = drv)) + geom_point(mapping = aes(x = displ, y = hwy, color = drv)) + theme_light() ``` ] .pull-right[ <!-- --> ] ]<!----> .panel[.panel-name[`theme_bw`] .pull-left[ ```r ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv, fill = drv)) + geom_point(mapping = aes(x = displ, y = hwy, color = drv)) + theme_bw() ``` ] .pull-right[ <!-- --> ] ]<!----> ]<!--end panel set--> --- .center[ # Bringing it All Together! ] .panelset[ .panel[.panel-name[Formula] - The following can be used a default template for ggplots: <br> <br> <img src = "data:image/png;base64,#img/mod3/formula.png" width = "40%" /> <br> .caption[Formula from [R for Data Science](https://r4ds.had.co.nz/data-visualisation.html)] <br> - Not all of these parameters need to be specified, defaults are often adequate ]<!----> .panel[.panel-name[Steps 1 and 2] <img src = "data:image/png;base64,#img/mod3/step1.png" width = "90%" /> <br> .caption[Figure from [R for Data Science](https://r4ds.had.co.nz/data-visualisation.html)] ]<!----> .panel[.panel-name[Steps 3 and 4] <img src = "data:image/png;base64,#img/mod3/step2.png" width = "90%" /> <br> .caption[Figure from [R for Data Science](https://r4ds.had.co.nz/data-visualisation.html)] ]<!----> .panel[.panel-name[Steps 5 and 6] <img src = "data:image/png;base64,#img/mod3/step3.png" width = "80%" /> <br> .caption[Figure from [R for Data Science](https://r4ds.had.co.nz/data-visualisation.html)] ]<!----> ]<!--end panel set--> --- .center[ # Scaffolding Resources ] <br> <br> [Data to Viz Website](https://www.data-to-viz.com/) <br> [esquisse Package](https://cran.r-project.org/web/packages/esquisse/vignettes/get-started.html)